package com.liveinstars.im.core;

import com.liveinstars.im.core.service.ChatServerService;
import com.liveinstars.im.domain.dao.model.ChatServer;
import com.liveinstars.im.entity.Msg;
import com.liveinstars.im.handler.ChatHandler;
import com.liveinstars.im.handler.MsgChatHandler;
import com.liveinstars.im.handler.ServerClientHandler;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.DefaultEventExecutorGroup;
import io.netty.util.concurrent.EventExecutorGroup;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.List;


@ChannelHandler.Sharable
@Service
public class ServerClientBootstrap {

	private static final Logger LOGGER = LoggerFactory.getLogger(ServerClientBootstrap.class);

	private SocketChannel socketChannel;

	@Autowired
	private ServerClientHandler serverClientHandler;

	@Autowired
	private ChatHandler chatHandler;
	@Autowired
	private MsgChatHandler msgChatHandler;

	private static final EventExecutorGroup group = new DefaultEventExecutorGroup(20);
	@Autowired
	private ChatServerService chatServerService;

	private EventLoopGroup eventLoopGroup;

	@Value("${netty.server.ip}")
	private String ip;
	/**
	 * 本机外网ip
	 */
	@Value("${netty.server.outip}")
	String outIp;

	@Value("${netty.server.port}")
	private int port;



	public void start() throws InterruptedException {
		eventLoopGroup = new NioEventLoopGroup();
		Bootstrap bootstrap = new Bootstrap();
		bootstrap.channel(NioSocketChannel.class);
		bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
		bootstrap.group(eventLoopGroup);
		bootstrap.handler(new ChannelInitializer<SocketChannel>() {
			@Override
			protected void initChannel(SocketChannel socketChannel)
					throws Exception {
				socketChannel.pipeline().addLast(
						new IdleStateHandler(0, 0, 200));
				socketChannel.pipeline().addLast(new ProtobufVarint32FrameDecoder());
				socketChannel.pipeline().addLast(new ProtobufDecoder(Msg.Message.getDefaultInstance()));
				socketChannel.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender());
				socketChannel.pipeline().addLast(new ProtobufEncoder());

				socketChannel.pipeline().addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
				socketChannel.pipeline().addLast(serverClientHandler);
				socketChannel.pipeline().addLast(msgChatHandler);
				socketChannel.pipeline().addLast(chatHandler);
			}
		});
		List<ChatServer> servers = chatServerService.listOnlineServer();
		for (ChatServer server : servers) {
			if (this.ip.equals(server.getIp()) && (this.port == Integer.parseInt(server.getPort()))) {
				// 本机不用链接
				continue;
			}
			ChannelFuture future = bootstrap.connect(server.getIp(),
					Integer.parseInt(server.getPort())).sync();
			if (future.isSuccess()) {
				socketChannel = (SocketChannel) future.channel();
				// MessageBack loginMsg = new MessageBack(MsgType.SERVER_LOGIN);
				Msg.ServerLoginMessage.Builder builder = Msg.ServerLoginMessage
						.newBuilder();
				Msg.ServerLoginMessage loginMsg = builder
						.setIp(ip)
						.setPort(port).build();
				Msg.Message.Builder b = Msg.Message.newBuilder();
				Msg.Message m = b.setServerLoginMessage(loginMsg)
						.setMessageType(Msg.MessageType.SERVER_LOGIN).build();
				LOGGER.info("send ServerLoginMessage " + ip + ":" + port);
				socketChannel.writeAndFlush(m);
				LOGGER.info("链接服务器 " + server.getIp() + ":" + server.getPort()
						+ "  成功。");
				String serverId = server.getIp() + ":" + server.getPort();
				Session session = new Session(socketChannel, serverId);
				SessionManager.add(session);
			}
		}
	}

	public void shutdown() {
		eventLoopGroup.shutdownGracefully();
	}
}
